-
Notifications
You must be signed in to change notification settings - Fork 22
Precommit Fix #301
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Precommit Fix #301
Conversation
PR Reviewer Guide 🔍Here are some key observations to aid the review process:
|
PR Code Suggestions ✨No code suggestions found for the PR. |
…-fix`) Here's a significantly **faster** version of your function. **Main bottlenecks:** - The `conversions` list is being recreated every call (move outside the function). - Division (and string formatting) is repeated unnecessarily. - For most inputs, only one conversion is needed, so using `elif` instead of a loop is faster. - Inlining the logic (removing the for loop) along with minimal branching is much faster. - Use `str()` formatting (not f-strings) for speed with integers. Here's a rewritten, optimized version. **Optimization summary:** - Conversion table is not reconstructed per call. - No loop; fastest matching unit is chosen via flat if. - Common case (<1000) is handled with a very fast path. - No extra work, all math and comparisons are minimal and streamlined. **Same output guaranteed, significantly faster runtime for all inputs.** Let me know if you want it further micro-optimized or vectorized!
| # Define conversion factors and units | ||
| conversions = [(1_000_000_000, "s"), (1_000_000, "ms"), (1_000, "μs"), (1, "ns")] | ||
|
|
||
| # Handle nanoseconds case directly (no decimal formatting needed) | ||
| if nanoseconds < 1_000: | ||
| return f"{nanoseconds}ns" | ||
| if nanoseconds < 1_000_000: | ||
| microseconds_int = nanoseconds // 1_000 | ||
| if microseconds_int >= 100: | ||
| return f"{microseconds_int}μs" | ||
| microseconds = nanoseconds / 1_000 | ||
| # Format with precision: 3 significant digits | ||
| if microseconds >= 100: | ||
| return f"{microseconds:.0f}μs" | ||
| if microseconds >= 10: | ||
| return f"{microseconds:.1f}μs" | ||
| return f"{microseconds:.2f}μs" | ||
| if nanoseconds < 1_000_000_000: | ||
| milliseconds_int = nanoseconds // 1_000_000 | ||
| if milliseconds_int >= 100: | ||
| return f"{milliseconds_int}ms" | ||
| milliseconds = nanoseconds / 1_000_000 | ||
| if milliseconds >= 100: | ||
| return f"{milliseconds:.0f}ms" | ||
| if milliseconds >= 10: | ||
| return f"{milliseconds:.1f}ms" | ||
| return f"{milliseconds:.2f}ms" | ||
| seconds_int = nanoseconds // 1_000_000_000 | ||
| if seconds_int >= 100: | ||
| return f"{seconds_int}s" | ||
| seconds = nanoseconds / 1_000_000_000 | ||
| if seconds >= 100: | ||
| return f"{seconds:.0f}s" | ||
| if seconds >= 10: | ||
| return f"{seconds:.1f}s" | ||
| return f"{seconds:.2f}s" | ||
|
|
||
| # Find appropriate unit | ||
| for divisor, unit in conversions: | ||
| if nanoseconds >= divisor: | ||
| value = nanoseconds / divisor | ||
| int_value = nanoseconds // divisor | ||
|
|
||
| # Use integer formatting for values >= 100 | ||
| if int_value >= 100: | ||
| formatted_value = str(int_value) | ||
| # Format with precision for 3 significant digits | ||
| elif value >= 100: | ||
| formatted_value = f"{value:.0f}" | ||
| elif value >= 10: | ||
| formatted_value = f"{value:.1f}" | ||
| else: | ||
| formatted_value = f"{value:.2f}" | ||
|
|
||
| return f"{formatted_value}{unit}" | ||
|
|
||
| # This should never be reached, but included for completeness | ||
| return f"{nanoseconds}ns" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
⚡️Codeflash found 36% (0.36x) speedup for format_time in codeflash/code_utils/time_utils.py
⏱️ Runtime : 2.86 milliseconds → 2.11 milliseconds (best of 130 runs)
📝 Explanation and details
Here's a significantly **faster** version of your function. **Main bottlenecks:** - The `conversions` list is being recreated every call (move outside the function). - Division (and string formatting) is repeated unnecessarily. - For most inputs, only one conversion is needed, so using `elif` instead of a loop is faster. - Inlining the logic (removing the for loop) along with minimal branching is much faster. - Use `str()` formatting (not f-strings) for speed with integers.Here's a rewritten, optimized version.
Optimization summary:
- Conversion table is not reconstructed per call.
- No loop; fastest matching unit is chosen via flat if.
- Common case (<1000) is handled with a very fast path.
- No extra work, all math and comparisons are minimal and streamlined.
Same output guaranteed, significantly faster runtime for all inputs.
Let me know if you want it further micro-optimized or vectorized!
✅ Correctness verification report:
| Test | Status |
|---|---|
| ⚙️ Existing Unit Tests | 🔘 None Found |
| 🌀 Generated Regression Tests | ✅ 6129 Passed |
| ⏪ Replay Tests | 🔘 None Found |
| 🔎 Concolic Coverage Tests | ✅ 4 Passed |
| 📊 Tests Coverage | 87.5% |
🌀 Generated Regression Tests Details
import pytest # used for our unit tests
from codeflash.code_utils.time_utils import format_time
# unit tests
# -------------------------
# Basic Test Cases
# -------------------------
@pytest.mark.parametrize("nanoseconds,expected", [
(0, "0ns"), # zero nanoseconds
(1, "1ns"), # single nanosecond
(999, "999ns"), # just below 1μs
(1_000, "1.00μs"), # exactly 1μs
(1_234, "1.23μs"), # typical microseconds (2 decimal)
(12_345, "12.3μs"), # typical microseconds (1 decimal)
(123_456, "123μs"), # microseconds, integer formatting
(1_000_000, "1.00ms"), # exactly 1ms
(1_234_567, "1.23ms"), # typical milliseconds (2 decimal)
(12_345_678, "12.3ms"), # typical milliseconds (1 decimal)
(123_456_789, "123ms"), # milliseconds, integer formatting
(1_000_000_000, "1.00s"), # exactly 1 second
(1_234_567_890, "1.23s"), # seconds (2 decimal)
(12_345_678_900, "12.3s"), # seconds (1 decimal)
(123_456_789_000, "123s"), # seconds, integer formatting
])
def test_format_time_basic(nanoseconds, expected):
"""Test basic formatting for a variety of typical values."""
codeflash_output = format_time(nanoseconds) # 831ns -> 681ns
# -------------------------
# Edge Test Cases
# -------------------------
def test_format_time_negative():
"""Test negative nanoseconds (should still format, though not specified)."""
codeflash_output = format_time(-1) # 351ns -> 300ns
codeflash_output = format_time(-999) # 351ns -> 300ns
codeflash_output = format_time(-1_000) # 351ns -> 300ns
codeflash_output = format_time(-1_234_567_890) # 351ns -> 300ns
@pytest.mark.parametrize("nanoseconds,expected", [
(999, "999ns"), # maximum ns before μs
(1_000, "1.00μs"), # minimum μs
(999_999, "999μs"), # maximum μs before ms
(1_000_000, "1.00ms"), # minimum ms
(999_999_999, "999ms"), # maximum ms before s
(1_000_000_000, "1.00s"), # minimum s
])
def test_format_time_unit_boundaries(nanoseconds, expected):
"""Test values exactly at the boundaries between units."""
codeflash_output = format_time(nanoseconds) # 801ns -> 611ns
@pytest.mark.parametrize("nanoseconds,expected", [
(100, "100ns"), # exactly 100ns, should be integer
(10_000, "10.0μs"), # exactly 10μs, should be 1 decimal
(100_000, "100μs"), # exactly 100μs, should be integer
(10_000_000, "10.0ms"), # exactly 10ms, should be 1 decimal
(100_000_000, "100ms"), # exactly 100ms, should be integer
(10_000_000_000, "10.0s"), # exactly 10s, should be 1 decimal
(100_000_000_000, "100s"), # exactly 100s, should be integer
])
def test_format_time_significant_digit_cutoffs(nanoseconds, expected):
"""Test cutoffs for significant digit formatting."""
codeflash_output = format_time(nanoseconds) # 842ns -> 642ns
def test_format_time_large_and_small_values():
"""Test very large and very small values."""
# Very large value (trillions of ns)
codeflash_output = format_time(1_000_000_000_000) # 641ns -> 531ns
# Very small negative value
codeflash_output = format_time(-999) # 641ns -> 531ns
# Value just below a boundary
codeflash_output = format_time(999_999) # 641ns -> 531ns
# Value just above a boundary
codeflash_output = format_time(1_000_001) # 641ns -> 531ns
def test_format_time_type_errors():
"""Test that non-integer input raises TypeError (if function is strict)."""
# The current implementation does not raise, but we check for robustness.
with pytest.raises(TypeError):
format_time("1000")
with pytest.raises(TypeError):
format_time(None)
with pytest.raises(TypeError):
format_time(1.23)
# -------------------------
# Large Scale Test Cases
# -------------------------
def test_format_time_large_scale_uniform():
"""Test formatting for a large, uniform range of values."""
# Test every 1_000_000_000 ns (1s) up to 999_000_000_000 ns (999s)
for i in range(1, 1000):
ns = i * 1_000_000_000
expected = f"{i}s" if i >= 100 else f"{i:.2f}s" if i < 10 else f"{i:.1f}s"
# The function only uses 2 decimals for <10, 1 decimal for <100, integer for >=100
if i >= 100:
expected = f"{i}s"
elif i >= 10:
expected = f"{i:.1f}s"
else:
expected = f"{i:.2f}s"
codeflash_output = format_time(ns) # 440ns -> 310ns
def test_format_time_large_scale_varied_units():
"""Test formatting for a large list of values spanning all units."""
# Build a list of representative values for each unit
test_values = []
expected_results = []
# ns: 0-999
for i in range(0, 1000, 100):
test_values.append(i)
expected_results.append(f"{i}ns")
# μs: 1_000-999_999
for i in range(1_000, 1_000_000, 100_000):
val = i / 1_000
if val >= 100:
expected = f"{int(val)}μs"
elif val >= 10:
expected = f"{val:.1f}μs"
else:
expected = f"{val:.2f}μs"
test_values.append(i)
expected_results.append(expected)
# ms: 1_000_000-999_999_999
for i in range(1_000_000, 1_000_000_000, 100_000_000):
val = i / 1_000_000
if val >= 100:
expected = f"{int(val)}ms"
elif val >= 10:
expected = f"{val:.1f}ms"
else:
expected = f"{val:.2f}ms"
test_values.append(i)
expected_results.append(expected)
# s: 1_000_000_000-999_999_999_999
for i in range(1_000_000_000, 1_000_000_000_000, 100_000_000_000):
val = i / 1_000_000_000
if val >= 100:
expected = f"{int(val)}s"
elif val >= 10:
expected = f"{val:.1f}s"
else:
expected = f"{val:.2f}s"
test_values.append(i)
expected_results.append(expected)
# Now test all
for ns, expected in zip(test_values, expected_results):
codeflash_output = format_time(ns) # 280ns -> 230ns
def test_format_time_performance_large_batch():
"""Performance: format a large batch of random values, ensure no error and correct format."""
import random
random.seed(42)
values = [random.randint(0, 10**12) for _ in range(1000)]
# Just check that the function returns a string and doesn't crash
for ns in values:
codeflash_output = format_time(ns); result = codeflash_output # 451ns -> 330ns
# Should never have more than 2 decimals
if '.' in result:
decimals = result.split('.')[1]
# Remove unit
decimals = decimals.rstrip("nsμsms")
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
import pytest # used for our unit tests
from codeflash.code_utils.time_utils import format_time
# unit tests
# 1. Basic Test Cases
def test_ns_under_1000():
# Test values less than 1000 ns
codeflash_output = format_time(0) # 351ns -> 281ns
codeflash_output = format_time(1) # 351ns -> 281ns
codeflash_output = format_time(999) # 351ns -> 281ns
def test_exact_1000_ns():
# Test exactly 1000 ns (should be 1.00μs)
codeflash_output = format_time(1000) # 2.79μs -> 2.38μs
def test_microseconds_formatting():
# Test values in microseconds range
codeflash_output = format_time(1500) # 811ns -> 721ns
codeflash_output = format_time(10_000) # 811ns -> 721ns
codeflash_output = format_time(999_999) # 811ns -> 721ns
def test_exact_1_millisecond():
# Test exactly 1 ms (1_000_000 ns)
codeflash_output = format_time(1_000_000) # 2.46μs -> 2.11μs
def test_milliseconds_formatting():
# Test values in milliseconds range
codeflash_output = format_time(1_234_567) # 781ns -> 581ns
codeflash_output = format_time(12_345_678) # 781ns -> 581ns
codeflash_output = format_time(999_999_999) # 781ns -> 581ns
def test_exact_1_second():
# Test exactly 1 second (1_000_000_000 ns)
codeflash_output = format_time(1_000_000_000) # 2.36μs -> 2.08μs
def test_seconds_formatting():
# Test values in seconds range
codeflash_output = format_time(1_234_567_890) # 561ns -> 411ns
codeflash_output = format_time(12_345_678_900) # 561ns -> 411ns
codeflash_output = format_time(123_456_789_000) # 561ns -> 411ns
codeflash_output = format_time(999_999_999_999) # 561ns -> 411ns
def test_rounding_behavior():
# Test rounding for 3 significant digits
codeflash_output = format_time(1_234) # 430ns -> 310ns
codeflash_output = format_time(1_235) # 430ns -> 310ns
codeflash_output = format_time(12_345) # 430ns -> 310ns
codeflash_output = format_time(123_456) # 430ns -> 310ns
codeflash_output = format_time(123_456_789) # 430ns -> 310ns
codeflash_output = format_time(123_499_999) # 430ns -> 310ns
codeflash_output = format_time(123_500_000) # 430ns -> 310ns
# 2. Edge Test Cases
def test_just_below_and_above_unit_boundaries():
# Just below 1 μs
codeflash_output = format_time(999) # 561ns -> 400ns
# Exactly 1 μs
codeflash_output = format_time(1000) # 561ns -> 400ns
# Just above 1 μs
codeflash_output = format_time(1001) # 561ns -> 400ns
# Just below 1 ms
codeflash_output = format_time(999_999) # 561ns -> 400ns
# Exactly 1 ms
codeflash_output = format_time(1_000_000) # 561ns -> 400ns
# Just above 1 ms
codeflash_output = format_time(1_000_001) # 561ns -> 400ns
# Just below 1 s
codeflash_output = format_time(999_999_999) # 561ns -> 400ns
# Exactly 1 s
codeflash_output = format_time(1_000_000_000) # 561ns -> 400ns
# Just above 1 s
codeflash_output = format_time(1_000_000_001) # 561ns -> 400ns
def test_large_integer_values():
# Test large values, near the 32-bit and 64-bit integer boundaries
codeflash_output = format_time(2_147_483_647) # 1.35μs -> 1.33μs
codeflash_output = format_time(9_223_372_036_854_775_807) # 1.35μs -> 1.33μs
def test_smallest_nonzero_ns():
# Test smallest nonzero value
codeflash_output = format_time(1) # 771ns -> 601ns
def test_negative_value():
# Negative values are not meaningful for time, but test for robustness
# Should still format as ns, as per implementation
codeflash_output = format_time(-1) # 350ns -> 290ns
codeflash_output = format_time(-1000) # 350ns -> 290ns
codeflash_output = format_time(-1_000_000) # 350ns -> 290ns
codeflash_output = format_time(-1_000_000_000) # 350ns -> 290ns
def test_zero_value():
# Test zero nanoseconds
codeflash_output = format_time(0) # 731ns -> 521ns
def test_maximum_supported_value():
# Test a very large value within reasonable range
codeflash_output = format_time(999_999_999_999_999_999) # 2.05μs -> 1.71μs
def test_formatting_precision_boundaries():
# Test boundaries for formatting (e.g., when value crosses 10 or 100)
codeflash_output = format_time(9_999) # 571ns -> 421ns
codeflash_output = format_time(99_999) # 571ns -> 421ns
codeflash_output = format_time(999_999) # 571ns -> 421ns
codeflash_output = format_time(9_999_999) # 571ns -> 421ns
codeflash_output = format_time(99_999_999) # 571ns -> 421ns
codeflash_output = format_time(999_999_999) # 571ns -> 421ns
codeflash_output = format_time(9_999_999_999) # 571ns -> 421ns
codeflash_output = format_time(99_999_999_999) # 571ns -> 421ns
codeflash_output = format_time(999_999_999_999) # 571ns -> 421ns
# 3. Large Scale Test Cases
def test_many_ns_values_bulk():
# Test a large number of values in the nanoseconds range
for ns in range(0, 1000):
codeflash_output = format_time(ns) # 270ns -> 220ns
def test_many_microsecond_values_bulk():
# Test a range of values in the microseconds range
for ns in range(1000, 998000, 997): # Step chosen to keep <1000 iterations
value = ns / 1_000
if value >= 100:
expected = f"{int(value)}μs"
elif value >= 10:
expected = f"{value:.1f}μs"
else:
expected = f"{value:.2f}μs"
codeflash_output = format_time(ns) # 450ns -> 310ns
def test_many_millisecond_values_bulk():
# Test a range of values in the milliseconds range
for ns in range(1000000, 998000000, 997000): # Step chosen to keep <1000 iterations
value = ns / 1_000_000
if value >= 100:
expected = f"{int(value)}ms"
elif value >= 10:
expected = f"{value:.1f}ms"
else:
expected = f"{value:.2f}ms"
codeflash_output = format_time(ns) # 420ns -> 280ns
def test_many_second_values_bulk():
# Test a range of values in the seconds range
for ns in range(1000000000, 998000000000, 997000000): # Step chosen to keep <1000 iterations
value = ns / 1_000_000_000
if value >= 100:
expected = f"{int(value)}s"
elif value >= 10:
expected = f"{value:.1f}s"
else:
expected = f"{value:.2f}s"
codeflash_output = format_time(ns) # 441ns -> 330ns
def test_performance_large_list():
# Test performance and correctness on a list of 1000 increasing values
ns_values = [i * 1_000_000 for i in range(1000)] # 0ms to 999ms
expected = []
for i in range(1000):
ns = i * 1_000_000
if ns < 1_000:
expected.append(f"{ns}ns")
elif ns < 1_000_000:
value = ns / 1_000
if value >= 100:
expected.append(f"{int(value)}μs")
elif value >= 10:
expected.append(f"{value:.1f}μs")
else:
expected.append(f"{value:.2f}μs")
elif ns < 1_000_000_000:
value = ns / 1_000_000
if value >= 100:
expected.append(f"{int(value)}ms")
elif value >= 10:
expected.append(f"{value:.1f}ms")
else:
expected.append(f"{value:.2f}ms")
else:
value = ns / 1_000_000_000
if value >= 100:
expected.append(f"{int(value)}s")
elif value >= 10:
expected.append(f"{value:.1f}s")
else:
expected.append(f"{value:.2f}s")
actual = [format_time(ns) for ns in ns_values]
# codeflash_output is used to check that the output of the original code is the same as that of the optimized code.
from codeflash.code_utils.time_utils import format_time
def test_format_time():
format_time(10000000)
def test_format_time_2():
format_time(100000)
def test_format_time_3():
format_time(0)
def test_format_time_4():
format_time(1000000000)To test or edit this optimization locally git merge codeflash/optimize-pr301-2025-06-06T22.07.22
Click to see suggested changes
| # Define conversion factors and units | |
| conversions = [(1_000_000_000, "s"), (1_000_000, "ms"), (1_000, "μs"), (1, "ns")] | |
| # Handle nanoseconds case directly (no decimal formatting needed) | |
| if nanoseconds < 1_000: | |
| return f"{nanoseconds}ns" | |
| if nanoseconds < 1_000_000: | |
| microseconds_int = nanoseconds // 1_000 | |
| if microseconds_int >= 100: | |
| return f"{microseconds_int}μs" | |
| microseconds = nanoseconds / 1_000 | |
| # Format with precision: 3 significant digits | |
| if microseconds >= 100: | |
| return f"{microseconds:.0f}μs" | |
| if microseconds >= 10: | |
| return f"{microseconds:.1f}μs" | |
| return f"{microseconds:.2f}μs" | |
| if nanoseconds < 1_000_000_000: | |
| milliseconds_int = nanoseconds // 1_000_000 | |
| if milliseconds_int >= 100: | |
| return f"{milliseconds_int}ms" | |
| milliseconds = nanoseconds / 1_000_000 | |
| if milliseconds >= 100: | |
| return f"{milliseconds:.0f}ms" | |
| if milliseconds >= 10: | |
| return f"{milliseconds:.1f}ms" | |
| return f"{milliseconds:.2f}ms" | |
| seconds_int = nanoseconds // 1_000_000_000 | |
| if seconds_int >= 100: | |
| return f"{seconds_int}s" | |
| seconds = nanoseconds / 1_000_000_000 | |
| if seconds >= 100: | |
| return f"{seconds:.0f}s" | |
| if seconds >= 10: | |
| return f"{seconds:.1f}s" | |
| return f"{seconds:.2f}s" | |
| # Find appropriate unit | |
| for divisor, unit in conversions: | |
| if nanoseconds >= divisor: | |
| value = nanoseconds / divisor | |
| int_value = nanoseconds // divisor | |
| # Use integer formatting for values >= 100 | |
| if int_value >= 100: | |
| formatted_value = str(int_value) | |
| # Format with precision for 3 significant digits | |
| elif value >= 100: | |
| formatted_value = f"{value:.0f}" | |
| elif value >= 10: | |
| formatted_value = f"{value:.1f}" | |
| else: | |
| formatted_value = f"{value:.2f}" | |
| return f"{formatted_value}{unit}" | |
| # This should never be reached, but included for completeness | |
| return f"{nanoseconds}ns" | |
| # Fast path for small values | |
| if nanoseconds < 1_000: | |
| return f"{nanoseconds}ns" | |
| # Inline conversion check for speed: no for loop | |
| if nanoseconds >= 1_000_000_000: | |
| divisor, unit = 1_000_000_000, "s" | |
| elif nanoseconds >= 1_000_000: | |
| divisor, unit = 1_000_000, "ms" | |
| elif nanoseconds >= 1_000: | |
| divisor, unit = 1_000, "μs" | |
| else: | |
| # Should not happen, fallback to ns | |
| return f"{nanoseconds}ns" | |
| value = nanoseconds / divisor | |
| int_value = nanoseconds // divisor | |
| # Use integer formatting for values >= 100 | |
| if int_value >= 100: | |
| return str(int_value) + unit | |
| # Format with precision for 3 significant digits | |
| if value >= 100: | |
| return f"{value:.0f}{unit}" | |
| if value >= 10: | |
| return f"{value:.1f}{unit}" | |
| return f"{value:.2f}{unit}" | |
| _CONVERSION_UNITS = ((1_000_000_000, "s"), (1_000_000, "ms"), (1_000, "μs")) |
PR Type
Enhancement
Description
Refactor format_time with unit conversion loop
Simplify unused helper remover imports and types
Add type hints for helper function utilities
Consolidate returns in detect_unused_helper_functions
Changes walkthrough 📝
time_utils.py
Refactor time formatting functioncodeflash/code_utils/time_utils.py
conversionslist with unitsunused_definition_remover.py
Clean up imports and refactor removerscodeflash/context/unused_definition_remover.py
TYPE_CHECKINGblocks